查看原文
其他

数据城堡参赛代码实战篇(一)---手把手教你使用pandas

2017-06-24 文文 Python爱好者社区

作者:文文  【数据挖掘日记、分享学习经验,心得

个人公众号:小小挖掘机   

小编们最近参加了数据城堡(http://www.pkbigdata.com/)举办的“大学生助学金精准资助预测”比赛,分组第19名的成绩进入了复赛,很激动有木有!在上一篇文章中,小编带大家回顾了参赛的心路历程,虽然看上去生动有趣,十分轻松,但是小编们在背后也是付出了不少的汗水呀。本篇,小编文文将带你一起分析如何用pandas来对官方给出的数据进行处理和分析。

1 引言

在进入正题之前呢,我们先来了解两件事情:pandas和官方数据。

1.1Pandas

首先,什么是pandas,相信很多数据挖掘爱好者对此已经非常熟悉,那么你可以直接跳过此处。Pandas 是python的一个数据分析包,提供了大量能使我们快速便捷地处理数据的函数和方法。在代码中使用pandas,首先需要导入:

import pandas as pd

它主要的数据结构有如下两种:Series

Series类似于一维数组对象,它由一组数据以及一组与之相关的数据标签组成,简单的Series可以按下面的方式进行创建:

obj=pd.Series([4,7,5,3])

输出如下:

0 4
1 7
2 5
3 3

其中,第一列是Series的索引列(index),第二列是数值列(values)。

DataFrame

DataFrame是一个表格型的数据结构,既有行索引又有列索引。行索引称为index,标示每一行数据,列索引称为columns,标示每一列数据。可以简单理解为一个数据表,列索引为数据表中除主键外的一个个字段,行索引相当于数据表中每一条数据的主键值。通过dict来创建DataFrame可以按如下的方式:

data={
'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
'year':[2001,2001,2002,2001,2002],
'pop':[1.5,1.7,3.6,2.4,2.9]
}
frame=pd.DataFrame(data)

如果不指定索引,结果中会自动加入行索引,而dict中的key则将作为列索引,输出如下:

pop state year
0   1.5     Ohio 2000
1   1.7     Ohio 2001
2   3.6     Ohio 2002
3   2.4     Neva 2001
4   2.9     Neva 2002

1.2 官方数据

数据总体描述

数据分为两组,分别是训练集和测试集,每一组都包含大约1万名学生的信息纪录:

图书借阅数据borrow_train.txt和borrow_test.txt、

一卡通数据card_train.txt和card_test.txt、

寝室门禁数据dorm_train.txt和dorm_test.txt、

图书馆门禁数据library_train.txt和library_test.txt、

学生成绩数据score_train.txt和score_test.txt

助学金获奖数据subsidy_train.txt和subsidy_test.txt

数据详细描述

(1)图书借阅数据

    字段描述和示例如下:

    学生id,借阅日期,图书名称,图书编号

    9708,2014/2/25,"我的英语日记/ (韩)南银英著  (韩)卢炫廷插图","H315 502"

    6956,2013/10/27,"解读联想思维: 联想教父柳传志","K825.38=76 547"

    9076,2014/3/28,"公司法 gong si fa = = Corporation law / 范健, 王建文著 eng"

(2)一卡通数据

    字段描述和示例如下:

    学生id,消费类别,消费地点,消费方式,消费时间,消费金额,剩余金额

    1006,"POS消费","地点551","淋浴","2013/09/01 00:00:32","0.5","124.9"

    1406,"POS消费","地点78","其他","2013/09/01 00:00:40","0.6","373.82"

    13554,"POS消费","地点6","淋浴","2013/09/01 00:00:57","0.5","522.37"

(3)寝室门禁数据

    字段描述和示例如下:

    学生id,具体时间,进出方向(0进寝室,1出寝室)

    13126,"2014/01/21 03:31:11","1"

    9228,"2014/01/21 10:28:23","0"

(4)图书馆门禁数据

    图书馆的开放时间为早上7点到晚上22点,门禁编号数据在2014/02/23之前只有“编号”信息,之后引入了“进门、出门”信息,还有些异常信息为null,请参赛者自行处理。

    字段描述和示例如下:

    学生id,门禁编号,具体时间

    3684,"5","2013/09/01 08:42:50"

    7434,"5","2013/09/01 08:50:08"

    8000,"进门2","2014/03/31 18:20:31"

    5332,"小门","2014/04/03 20:11:06"

    7397,"出门4","2014/09/04 16:50:51"

(5)学生成绩数据

    注:成绩排名的计算方式是将所有成绩按学分加权求和,然后除以学分总和,再按照学生所在学院排序。

    学生id,学院编号,成绩排名

    0,9,1

    1,9,2

    8,6,1565

    9,6,1570

(6)助学金数据

    字段描述和示例如下:

    学生id,助学金金额(分隔符为半角逗号)

    10,0

    22,1000

    28,1000

    64,1500

    650,2000

2 数据处理实战

官方给出了示例代码,对一卡通数据以及学生成绩进行了处理,获得了一个学生在学院的成绩排名、消费总金额,平均消费金额以及单次最大消费金额等等特征,这些就不一一赘述其处理过程啦。这里,小编想通过pandas介绍一下我们是如何对数据进行处理,得到我们想要的特征的。

2.1 恩格尔系数计算

既然官方的一卡通数据给出了消费类别,有食品、超市、淋浴等等,我们很容易想到的是恩格尔系数,它表示食品支出占一个人总支出的比重。那么下面小编将根据官方给出的数据,带你一步步分析计算每个人的恩格尔系数。

1)读取数据

我们利用pandas的read_csv方法将数据读入到DataFrame中:

#没有columns数据,header属性设置为None
card_df=pd.read_csv('card_train.txt',header=None)

由于官方没有给定colunms,我们对columns属性进行赋值:

card_df.columns = ['id','consume','where','how','time','amount','remainder']

我们可以先来看一下前10行的数据,使用head()方法

print (card_df.head(10))

输出结果如下:

id   consume where how time amount remainder
1006   POS消费 地点551 淋浴 2013/09/01   0.50  124.90
1006   POS消费 地点551 淋浴 2013/09/01   0.50  124.90
1968   POS消费 地点159 淋浴 2013/09/01   0.10  200.14
1968   POS消费 地点159 淋浴 2013/09/01   0.10  200.14
1406   POS消费 地点660 开水 2013/09/01   0.01  374.42
1406   POS消费 地点660 开水 2013/09/01   0.01  374.42
1406   POS消费 地点78 其他 2013/09/01   0.60  373.82
1406   POS消费 地点78 其他 2013/09/01   0.60  373.82
13554  POS消费 地点6 淋浴 2013/09/01   0.50  522.37
13554  POS消费 地点6 淋浴 2013/09/01   0.50  522.37

天呐,这有点太乱了吧,没关系,小编带你一步步简化数据!

2)数据汇总

想要计算恩格尔系数,需要知道每个人的食品支出以及消费总支出,即我们想要看到的结果是这样子的:

id 图书馆 食堂 超市 开水 教务处 文印中心 校医院.....
01  0.0  100.0 20.0 5.0   3.0   10.0   100.0
02  0.0  100.0 20.0 5.0   3.0   10.0   100.0
02  0.0  100.0 20.0 5.0   3.0   10.0   100.0

下面小编将用两种方法带你得到这样的汇总数据

  • 使用groupby()方法

groupby,顾名思义,就是对数据进行分组的意思。回顾一下上一节中提到的原始数据以及我们的目标数据,可以看出我们首先需要按照学生的id进行分组,再按照消费类别进行分组,对分组后的数据,我们还需要一个加总的方法来得到每个学生在每个类别下的总支出。groupby的使用如下:

#首先,使用groupby,指定首先按照id进行分组,再按照how列进行分组,
#对于分#组后的数据,我们取amount列,并进行加总处理
card_group=card_df.groupby(['id','how'])['amount'].sum()

得到的结果如下:

id how
0      图书馆 84.40
      开水 429.58
      文印中心 0.30
      校车 417.49
      淋浴 12.30
      超市 839.68
      食堂 647.81
1      图书馆 324.20
      开水 265.97
      教务处 29.30
      文印中心 96.40
      校车 119.40
      洗衣房 25.02
      淋浴 22.50
      超市 514.30
      食堂 1540.60

就快要成功啦,但是离我们的目标还差一点,我们需要将以how命名的行标签转换成列标签,就可以得到我们想要的结果啦。想要行标签转换成列标签,我们可以使用pandas提供的unstack方法,具体如下:

card_group=card_group.unstack('how')

unstack方法将我们指定的行标签转换成列标签,我们可以看一下此时的输出结果:


Name: amount, dtype: float64
how 其他 图书馆 开水 教务处 文印中心 校医院 校车 洗衣房 淋浴 超市 食堂
id                                                                      
0     NaN 84.40   429.58   NaN 0.3     NaN 417.49    NaN 12.30  839.68   647.81
1     NaN 324.20   265.97  29.3   96.4     NaN 119.40   25.02   22.50  514.30  1540.60
8     NaN 425.90  2440.94   NaN 2.6     NaN 2211.45   4.50   39.83    0.00   387.15  

得到上面的结果,我们马上就要大功告成啦,但是我们发现结果中有NAN的数据,表明该学生没有该类别的消费记录。我们可以用fillna方法将其转换:

#用0替换NaN值,同时直接覆盖原DataFrame
card_group.fillna(0,inplace=True)

再次看一下我们的输出,大功告成!

Name: amount, dtype: float64
how 其他 图书馆 开水 教务处 文印中心 校医院 校车 洗衣房 淋浴 超市 食堂
id
0     0.0   84.40   429.58   0.0    0.3     0.0   417.49    0.0   12.30  839.68   647.81
1     0.0  324.20   265.97  29.3   96.4     0.0   119.40   25.02   22.50  514.30  1540.60
8     0.0  425.90  2440.94   0.0    2.6     0.0  2211.45   4.50   39.83    0.00   387.15
  • 使用pivot_table()方法

如果你是一名熟练的excel爱好者,很容易想到的是使用数据透视表来实现我们所要的结果。没错,pandas也提供了数据透视表的功能,相对于使用groupby来说,数据透视表更加的便捷快速,代码如下:

#第一个参数指定我们需要计算的列,第二个参数指定行标签,第三个参数代表列标签,
#aggfunc参数指定对需要计算的列的计算方法,此处用sum方法进行汇总,如果是计数,使用len方法
card_group=card_df.pivot_table('amount',index=['id'],columns=['how'],aggfunc=sum)

结果如下:

how 其他 图书馆 开水 教务处 文印中心 校医院 校车 洗衣房 淋浴 超市 食堂
id                                                                      
0     NaN 84.40   429.58   NaN 0.3     NaN 417.49    NaN 12.30  839.68   647.81
1     NaN 324.20   265.97  29.3   96.4     NaN 119.40   25.02   22.50  514.30  1540.60
8     NaN 425.90  2440.94   NaN 2.6     NaN 2211.45   4.50   39.83    0.00   387.15


再对上面的结果中的NaN进行替换,即可得到我们想要的结果,此处不再赘述。

3)计算恩格尔系数

对于上一节中的得到的汇总数据,我们首先需要计算学生的总消费金额,具体如下:

#使用sum()方法
#指定axis=1,表示对每一行的数据进行加总,默认为0
#将计算的结果赋值到‘总计’列
card_group['总计']=card_group.sum(axis=1,skipna=False)

得到了汇总结果,接下来就好处理了,仅需要用食堂消费除以总消费即可得到每一个人的恩格尔系数:

card_group['恩格尔1']=card_group['食堂']/card_group['总计']

我们来看一下结果:

print card_group[['食堂','总计','恩格尔1']]

输出如下:

how 食堂 总计 恩格尔1
id                              
0       647.81  2431.56  0.266417
1      1540.60  2937.69  0.524426
8       387.15  5522.37  0.070106
9      1899.60  7402.91  0.256602
10      944.84  2907.44  0.324973
11      333.40  2670.80  0.124832
19      513.31  1513.06  0.339253

最后我们使用to_csv方法将数据写入到csv文件中即可。

card_group.to_csv('card_train.csv',encoding='gbk')

至此,我们计算恩格尔系数的目标大功告成!很激动有木有!

3 总结

本篇带你详细介绍了在参与此次比赛过程中使用pandas计算恩格尔系数的主要过程,重点介绍了groupby()和pivot_table()方法,相信大家已经初步领略到了pandas的神奇之处,更多关于pandas的使用方法,可以参考《使用python进行数据分析》一书。


关注公众号,“Python爱好者社区”,回复“爬虫”即可获取崔老师爬虫免费学习视频。


Python爱好者社区


为大家提供与Python相关的最新技术和资讯。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存